home *** CD-ROM | disk | FTP | other *** search
- #ifndef __TREEOBJ__
- #define __TREEOBJ__
-
- #ifndef __TYPES__
- #include <Types.h>
- #endif
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __EVENTS__
- #include <Events.h>
- #endif
-
- #ifndef __MEMORY__
- #include <Memory.h>
- #endif
-
- #define NO_EDIT 0 /* System edit type. */
-
-
- /********/
-
-
- #define EMPTYOBJ 0
- #define ROOTOBJ 1
- #define UNDOOBJ 2
- #define UNDOTASKOBJ 3
- #define UNDOPARTOBJ 4
- #define WFMTOBJ 5
- #define CTLOBJ 6
-
- #define kCStr 0
- #define kPStr 1
- #define kSDataBlock 2
- #define kLDataBlock 3
-
- #ifdef powerc
- #pragma options align=mac68k
- #endif
- struct FileRec;
- typedef struct FileRec *FileRecPtr, **FileRecHndl;
- #ifdef powerc
- #pragma options align=reset
- #endif
-
- #ifdef powerc
- #pragma options align=mac68k
- #endif
- struct TreeObj;
- typedef struct TreeObj *TreeObjPtr, **TreeObjHndl;
- typedef long (*TreeObjProcPtr)(TreeObjHndl hndl, short message, long data);
- #ifdef powerc
- #pragma options align=reset
- #endif
-
- #ifdef powerc
- #pragma options align=mac68k
- #endif
- typedef struct TreeObj {
- short type;
- short numChildren;
- long dataSize;
- long treeID;
- TreeObjHndl parent;
- } TreeObj;
- #ifdef powerc
- #pragma options align=reset
- #endif
-
- #ifdef powerc
- #pragma options align=mac68k
- #endif
- long TUndoObj(TreeObjHndl hndl, short message, long data);
- typedef struct {
- TreeObjHndl root;
- FileRecHndl frHndl;
- Boolean disabled;
- short lastEditType;
- short undoDepth;
- short maxNumUndos;
- short numSaveUndos;
- } UndoObj;
- #ifdef powerc
- #pragma options align=reset
- #endif
-
- #ifdef powerc
- #pragma options align=mac68k
- #endif
- long TUndoTaskObj(TreeObjHndl hndl, short message, long data);
- typedef struct {
- short editType;
- Point undoOrigin;
- Point redoOrigin;
- } UndoTaskObj;
- #ifdef powerc
- #pragma options align=reset
- #endif
-
- #ifdef powerc
- #pragma options align=mac68k
- #endif
- long TUndoPartObj(TreeObjHndl hndl, short message, long data);
- typedef struct {
- short actionType;
- TreeObjHndl shndl;
- short scnum;
- TreeObjHndl dhndl;
- short dcnum;
- Boolean deepCopy;
- } UndoPartObj;
- #ifdef powerc
- #pragma options align=reset
- #endif
-
- #ifdef powerc
- #pragma options align=mac68k
- #endif
- struct VHFormatData {
- Handle text;
- char *header;
- char *data;
- };
- typedef struct VHFormatData VHFormatData;
- typedef VHFormatData *VHFormatDataPtr;
- #ifdef powerc
- #pragma options align=reset
- #endif
-
- #define mDerefUndo(hndl) ((UndoObj*)((*hndl) + 1))
- #define mDerefUndoTask(hndl) ((UndoTaskObj*)((*hndl) + 1))
- #define mDerefUndoPart(hndl) ((UndoPartObj*)((*hndl) + 1))
-
-
- /********/
-
-
- #define INITMESSAGE 0 /* Additional object initialization. */
- #define CREATEINIT 0 /* Object being initially created. */
- #define WINDOWINIT 1 /* Document/object being assigned to a window. */
- #define NOWINDOWINIT 2 /* Document/object being freed from a window. */
-
- #define FREEMESSAGE 1 /* Additional object disposal. */
-
- #define COPYMESSAGE 2 /* Additional object cloning. */
-
- #define UNDOMESSAGE 3 /* Additional object undo. */
- #define UNDOFROMDOC 0 /* Object leaving document. */
- #define UNDOTODOC 1 /* Object returning to document. */
-
- #define CONVERTMESSAGE 4 /* Hndl2ID or ID2Hndl conversions. */
- #define CONVERTTOID 0 /* Convert handle references to ID references. */
- #define CONVERTTOHNDL 1 /* Convert ID references to handle references. */
-
- #define FREADMESSAGE 5 /* Read object data from file. */
- #define FWRITEMESSAGE 6 /* Write object data to file. */
-
- #define HREADMESSAGE 7 /* Read object data from handle. */
- #define HWRITEMESSAGE 8 /* Write object data to handle. */
-
- #define HITTESTMESSAGE 9 /* Test if object was hit. */
- #define HITTESTOBJ 0 /* Test body of object for hit. */
- #define HITTESTGRABBER 1 /* Test sizing parts for hit. */
- #define CANBETARGET 2 /* Return true if object can become target. */
- #define CANTAKEKEYS 3 /* Return true if target can take keys. */
-
- #define GETRGNMESSAGE 10 /* Return object defining rect. */
- #define GETOBJRECTMESSAGE 11 /* Return object defining rect. */
- #define SETOBJRECTMESSAGE 12 /* Set object bounding box. */
- #define SECTOBJRECTMESSAGE 13 /* Check if rect intersects object bounding box. */
-
- #define GETBBOXMESSAGE 14 /* Return rect that contains entire graphic image. */
-
- #define DRAWMESSAGE 15 /* Draw some form of the object. */
- #define DRAWOBJ 0 /* Draw the object. */
- #define ERASEOBJ 1 /* Draw the object. */
- #define DRAWSELECT 2 /* Draw the selection portion of the object. */
- #define DRAWGHOST 3 /* Draw an xor-ghost (for dragging) of the image. */
- #define DRAWMASK 4 /* Draw a mask of the image (for offscreen layer masking.) */
-
- #define PRINTMESSAGE 16
-
- #define VHMESSAGE 17 /* Format View Hierarchy information for the object. */
-
- #define COMPAREMESSAGE 18 /* Compare data of two objects of same type. */
-
-
-
- #define DOUNDO 0
- #define DOREDO 1
-
-
-
- TreeObjHndl NewRootObj(short ctype, long size);
-
- /*
- ¶ Create a root object, i.e., one that has no parent object.
-
- INPUT: ctype Type of object to create, such as ROOTOBJ, WFMTOBJ, etc.
- size Initial size of root object. Note that there is a min-size table,
- so this is used only if it is greater than the default size. If
- the default size is what you want, just pass in 0 here.
-
- Create a root object, i.e., one that has no parent object.
-
- Defining a generic document architecture that is flexible enough to handle the many and varied
- document types, yet simple enough to justify using it, can be difficult.
-
- The document structure type chosen here is a simple hierarchy. For simple document types, the
- hierarchical feature can simply be ignored. All of the member objects of the document can simply be
- children of the root object. This gives the document a linear feel, (all objects are at the same
- level in the hierarchy), which is all that is needed for a lot of applications.
-
- For more complex document structures that have many data types which inter-relate, the hierarchical
- model is quite useful. The sample given here is a draw program. The draw example demonstrates both
- the linear document type (no grouping used) and the hierarchical document type (grouping used).
- If no grouping is used, then all of the objects added to the document are children of the root
- object. The objects are arranged linearly off the root document object. If some of the objects
- are grouped, a group object is first added to the root object, and then the selected objects are
- moved so that they are children of the group object. Now the document is no longer linear. The
- root object has children, some of which may be group objects. These group objects in turn have
- children.
-
- This sort of hierarchical support makes grouping of objects in a draw-type program trivial.
- It naturally represents the organization of the objects within the document.
-
- An additional benefit of managing the objects in a document in such a standardized way is that
- additional application features such as undo/redo can be automatically supported. Whenever a change
- is to be made to the document, one of a few document-hierarchy-management calls is made first.
- The different operations that can be done to the hierarchical document are:
-
- All that is needed to create a root object is to call NewRootObj. A root object is simply a standard
- object with no parent. (The “parent” field for a root object is therefore nil.)
-
-
- The default AppsToGo object is initially created with a root object. The root object can have data
- stored directly into the data area within it, or instead, children can be added to the root object.
- The more flexible choice, of course, is to add children to the root object.
-
-
- To add children to the root object, you would simply call NewChild, giving the root object as the
- object to add a child to. See NewChild for more information on this.
- */
-
-
-
-
- TreeObjHndl NewChild(short editType, TreeObjHndl parentHndl, short childNum, short ctype, long size);
-
- /*
- ¶ Creates a child of specified type and adds it to parent at specified location.
-
- Creates a child of specified type and adds it to parent at specified location.
- Returns nil upon failure.
-
- NewChild is one of six operations that can be done to a hierarchical document that has automatic
- undo/redo support. The six operations are:
-
- NewChild
- DisposeChild
- CopyChild
- MoveChild
- ModifyChild
- SwapChildren
-
- These six operations cover the various operations that can be performed to one or more of the
- document objects. Children can be added, removed, copied, moved, modified, or swapped. If these
- calls are used to modify objects within the document hierarchy, then the editing operations done to
- the document can automatically be recorded for undo/redo purposes.
-
- To better understand the hierarchical document architecture, we will talk about more than just
- NewChild here. Since many of the function inter-relate, it is best to discuss them in a group
- at some point.
-
- Looking at a sample NewChild call and its prototype, we have:
-
- NewChild, if successful, returns a handle for the child object added to the document.
-
- The parameters are:
- editType: Application edit type for which this document modification is being done.
- parentHndl: The child created will be added as a child to this object.
- childNum: The child will be added to the parent as this child number.
- ctype: The child will be of this type.
- size: The child will be created this initial size (if size is greater than minimum).
-
- NewChild must have a parent declared. This begs the question of where the initial parent comes from.
- At some point, NewRootObj must be called to create the initial root parent. As would be expected,
- the root object has no parent. Once there is an initial root object, children can then be added to
- the document via NewChild.
-
- The editType of the NewChild call is used for automatically tracking undo/redo. Many individual
- operations may be done to the document that are all for the same editing operation. Let's say that
- you have a word-processor application that has paragraph objects. If your document has 27
- paragraphs, then you have 27 children off the root object. The order of the children is the order
- of the paragraphs in your document.
-
- Let's now say that the user has selected some text. The text selected starts in the middle of
- paragraph 3, goes through paragraphs 4-5, and through half of the text in paragraph 6. The user
- then deletes this text. We may have declared this type of edit to be of type DELETE_EDIT.
- The edits to the document that we will perform are:
-
- 1) Modify paragraph 3 by removing the selected text and keeping the unselected text.
- 2) Delete paragraphs 4-5.
- 3) Modify paragraph 6 by removing the selected text and keeping the unselected text.
-
- For step 1, we would first use ModifyChild. The prototype for ModifyChild is:
-
- OSErr ModifyChild(short editType, TreeObjHndl phndl, short childNum, Boolean deepCopy);
-
- ModifyChild makes a copy of the object and places the copy in the undo hierarchy. We are now free
- to modify the object any way we see fit. If the user chooses to undo the change, the undo code
- simply swaps the data of the modified object with the copy that was saved in the undo hierarchy.
- If the user later chooses to redo the edit, the undo code simply swaps the data again to perform
- the redo.
-
- NOTE: ModifyChild may fail, since a copy of the object is made. There may not be enough memory
- for this copy to be created. If this is so, then memFullErr will be returned.
-
- The parameters are:
- editType: Application edit type for which this document modification is being done.
- parentHndl: Parent of the child being modified.
- childNum: Child number (of the parent) being modified.
- deepCopy: If true, the children of this child are also copied into the undo hierarchy.
-
- The editType parameter is used to determine if this document modification is of the same
- edit type as previous document modifications. If it is, then the operation is grouped
- with the other operations. This is all done for the purposes of undo/redo. Multiple objects
- may be modified in a single edit, and these modifications all have to be undone/redone with
- a single undo/redo.
-
- If the editType is different than the last document modification, then a new undo group is
- started, and this operation is recorded in this new group.
-
- For the above example, we would make the following call to ModifyChild prior to removing
- the selected text from paragraph 3:
-
- err = ModifyChild(DELETE_EDIT, root, 3, false);
-
- Of course, it would be a really odd application in which the '3' was hard-coded as in
- the above line.
-
- Now paragraphs 4 and 5 need to be deleted. This is done by using DisposeChild.
- The prototype for DisposeChild is:
- void DisposeChild(short editType, TreeObjHndl parentHndl, short childNum);
-
- Note that DisposeChild will succeed, as it doesn't have to create a new handle for the
- copy as ModifyChild does. HOWEVER: DisposeChild doesn't necessarily free up ram, as
- you would expect. All that occurs is that the child is moved into the undo hierarchy so
- that undo can move the child back into the document.
-
- To delete children 4 and 5, we would do the following:
-
- DisposeChild(DELETE_EDIT, root, 4);
- DisposeChild(DELETE_EDIT, root, 4);
-
- Note that for both calls we dispose of child number 4. This is because once the first child
- is disposed of, what used to be child 5 is now child 4.
-
- The last operation we would do is to declare our intent to change to the end child in the
- selection range. This would be done as follows:
- err = ModifyChild(DELETE_EDIT, root, 4, false);
-
- The delete (assuming no errors) has now been completed. Actually, the delete has occurred
- in either case. If there were errors, all that occurred is that the undo information wasn't
- recorded.
-
- Now let's say that the user selects a new range of text and deletes it, as well. We would
- do the same thing as above to delete the text. Here's the problem: The editType of this
- second text delete is the same as the first. Both document edits were of type DELETE_EDIT.
- This means that both operations were recorded under the same undo task. When the user
- chooses undo, both deletes will be undone. This isn't what we want.
-
- To fix this problem, we have to make one additional call. We need to call NewUndo.
- NewUndo closes out the old editing task. When you then make some document modification,
- it will be recorded in a separate undo task.
-
- NewUndo only takes a single parameter. Just pass it any handle in the document. Any
- object in the document can serve as a reference to the document.
-
-
- An object handle has 3 parts:
- 1) The header information.
- 2) The application-defined object data.
- 3) The child handle table.
-
-
- The object header is of the following form:
-
- typedef struct TreeObj {
- short type;
- short numChildren;
- long dataSize;
- long treeID;
- TreeObjHndl parent;
- } TreeObj;
-
- These fields are automatically filled out whenever an object is created via NewRootObj
- or NewChild.
-
- The application-defined data area is automatically initialized with 0's. When NewRootObj
- or NewChild is called, a size parameter is passed in. There is also a table of minimum sizes
- for each object type that needs to be defined. If the size passed in is smaller than the
- minimum size, then the minimum size is used as the data size instead.
-
- The minimum size table is a global array of longs called gMinTreeObjSize. Its definition is
- found in File.c. For each type of object defined, there needs to be a minimum size defined.
-
- There are some predefined object types. These are defined by the following:
-
- #define ROOTOBJ 1
- #define UNDOOBJ 2
- #define UNDOTASKOBJ 3
- #define UNDOPARTOBJ 4
- #define WFMTOBJ 5
- #define CTLOBJ 6
-
- These are the mandatory object types for supporting this implementation of the document
- structure and undo/redo features.
-
- Application-defined object types can start with type number 16. Type number 0 is reserved
- and is currently undefined. Types 7-15 are reserved for future objects that may be added
- to the DTS.Lib application framework.
-
- The numChildren field is initially 0 after calling either NewRootObj or NewChild.
-
- The dataSize is the effective data size after object creation, which is either the size passed
- in, or the minimum object size, whichever is greater.
-
- The treeID field is initially set to 0 by both NewRootObj and NewChild. This field is
- used to uniquely identify members of the hierarchy by ID. (More on this later.)
-
- The parent field is a reference to the handle which is the parent. As you would expect,
- objects created by NewRootObj have no parent, and therefore this field is nil.
-
-
- The application-defined data area starts immediately after the header information. As the
- structure of this portion is application-defined and variant, there is no structure pre-defined
- for it. Each object type will have a unique structure definition for this portion of the object.
-
-
- The final part of an object is the child handle table. The child handle table starts
- immediately after the data portion of the object. The size of the header structure plus
- the value in the dataSize field serves as an offset from the beginning of the object to
- the child handle table. Given the relationship between dataSize and the child handle
- table, it is important that the object isn't resized directly. There are calls for managing
- the data area and its size that take the child handle table into account. These are:
-
- OSErr AdjustDataSize(TreeObjHndl hndl, long delta);
- OSErr SetDataSize(TreeObjHndl hndl, long newSize);
- OSErr SlideData(TreeObjHndl hndl, long offset, long delta);
- void *GetDataPtr(TreeObjHndl hndl);
-
- AdjustDataSize alters the size of the data area, based on the delta passed in. If you wish
- to decrease the data area by one byte, for example, pass in a -1. AdjustDataSize does not
- reposition any of the data within the data area. It does move the child handle table so that
- it continues to be positioned immediately after the data area.
-
- SetDataSize does as expected. It specifically sets the data size to the designated
- size. It also does not shift the data, but does do the appropriate child handle table
- maintenance, just as AdjustDataSize does.
-
- SlideData operates the same as AdjustDataSize, plus it also slides some or all of the
- data in the data area. Use SlideData to insert or remove data at some location within
- the data area.
-
- GetDataPtr simply returns a pointer to the beginning of the data area. IT DOES NOT LOCK
- THE HANDLE!! If the handle needs locking, then you must do this yourself. Since the object
- is simply a handle, this poses no difficulties. (Unlock when you are done, of course.)
-
-
- The child handle table is automatically handled. There shouldn't be a reason that you need
- to manage or reference this yourself. If however you end up needing to do this, there
- are calls to manage the child handle table.
-
-
- Objects referencing other objects:
-
- Let's revisit the word-processor example. Once again, we have this paragraph-based word
- processor. The user selects some text. The cursor location (insertion point) must be kept.
- A reference to the starting object and an offset into the data of that object would serve as
- the cursor location reference.
-
- This reference to the paragraph object containing the insertion point could be kept as either
- a handle reference or a child number reference. Either would serve the purpose. Both would
- uniquely describe an object in the document. The handle reference would directly reference
- the object. The child number reference would indirectly reference the object. If we used
- child numbers as our reference and we desired to get the handle of the object, we would do
- something like the following:
-
- chndl = GetChildHndl(root, cnum);
-
- In our document example, all of the paragraph objects are children of the root object.
- In this case it would be a simple matter of getting the child handle. The child number
- reference would probably be stored in the root object, as it is a global piece of information
- for this document. We would probably want it saved with the document, which would occur
- automatically if it were stored in the root object.
-
- So, since they both seem to work, which is better? Is keeping the handle better, or is keeping
- the child number better? When saving a document, child numbers will be meaningful when the
- document is opened at a future date. References to handles aren't meaningful when saved to disk
- and then reloaded. For this reason it seems that child number should win out.
-
- But what if you wish to keep a reference to some arbitrary point in the document? What if you
- don't know what the parent of that object is? What if the object is at some arbitrary depth
- in the hierarchy? In this case, it seems pretty clear that we wish to use handle references
- instead of child number references, at least when the document is in memory.
-
- So what about handle references when saved to disk? We need these references to persist. To
- do this, we must convert them to something that saves meaningfully and can be converted back
- to handle references when the document is reopened.
-
- This is what the treeID field in the object header is for. When DoNumberTree is called,
- all of the objects in the hierarchy are uniquely numbered. DoNumberTree is automatically
- called by the shell just prior to the objects in a hierarchy are written to disk. In
- addition, prior to writing an object out to disk, the object is called with a message
- requesting it to convert any handle references it contains to treeID references. For each
- handle reference that needs to be converted, you need to call Hndl2ID to do the conversion.
- Hndl2ID depends on DoNumberTree already being called so that all of the treeID fields
- for all of the objects in the hierarchy are current.
-
- After calling the object with the handle-to-id conversion message, the object is written
- to disk. Once it is written, a message is sent to the object requesting it to covert the
- id back into a handle reference. For each reference converted, you need to call ID2Hndl
- to deconvert the reference back into a handle.
-
- When a document is opened, all of the objects are first read into memory. Once the entire
- document is in memory, DoNumberTree is called, and then each object in the document is
- sent a message requesting it to convert the converted handle references back into real
- handle references.
-
- The reason that the entire document must first be read is that the reference to another object
- may be to an object that is later in the document. Only after the entire document is read in
- is it possible to resolve all references to anywhere in the document.
-
- This messaging mechanism allows you to use handle references within your application without
- worrying about them persisting through a save/open cycle. So, given the above messaging
- mechanism, using either child number references or handle references is equally valid.
- Whatever seems easiest for a particular application is the one to use.
-
-
- There is a standard set of messages passed to objects. The above message is just one of these.
- See DoTreeObjMethod for a complete list of standard messages and descriptions.
-
- */
-
-
-
- void DisposeChild(short editType, TreeObjHndl parentHndl, short childNum);
- /*
- ** ¶ Disposes of the specified child and all offspring of that child.
- **
- ** INPUT: editType Edit type for undo posting (NO_EDIT for no posting).
- ** parentHndl Parent handle that owns child to dispose.
- ** childNum Child number to dispose.
- **
- **
- ** Disposes of the specified child and all offspring of that child. Note that, unless editType
- ** is NO_EDIT, all information necessary to undo this operation is automatically posted. */
-
-
-
- TreeObjHndl CopyChild(short editType, TreeObjHndl shndl, short scnum,
- TreeObjHndl dhndl, short dcnum, Boolean deepCopy);
- /*
- ** ¶ Copies specified child (and all offspring of that child, if desired).
- **
- ** INPUT: editType Edit type for undo posting (NO_EDIT for no posting).
- ** shndl Source parent handle for copy.
- ** scnum Source child number (of parent) to copy.
- ** dhndl Destination parent for copy.
- ** dcnum Destination child number (of parent) for copy.
- ** deepCopy True if children of copied child are to be copied too.
- ** RESULT TreeObjHndl Handle new new child created due to copy operation.
- **
- ** Copies the specified child (and all offspring of that child if deepCopy is true).
- ** Note that, unless editType is NO_EDIT, all information necessary to undo this operation
- ** is automatically posted. */
-
-
-
- OSErr MoveChild(short editType, TreeObjHndl shndl, short scnum, TreeObjHndl dhndl, short dcnum);
- /*
- ** ¶ Moves a child from one location on the tree to another.
- **
- ** INPUT: editType Type of edit for posting undo tasks. For no undo posting, then
- ** pass in NO_EDIT as a value.
- ** shndl Old parent handle (parent prior to move).
- ** scnum Old child number for the object to move.
- ** dhndl New parent handle (parent after the move).
- ** dcnum New child number after the ovject is moved.
- ** RESULT: OSErr Most likely error is memFulErr.
- **
- ** Moves a child from one location on the tree to another. This source and destination
- ** don't have to be the same tree. */
-
-
-
- OSErr ModifyChild(short editType, TreeObjHndl phndl, short cnum, Boolean deepCopy);
- /*
- ** ¶ Saves a copy of the child in the undo hierarchy for undo/redo purposes.
- **
- ** INPUT: editType Type of edit for posting undo tasks. For no undo posting, then
- ** pass in NO_EDIT as a value.
- ** phndl Parent handle of object to be modified.
- ** cnum Child number of the object to modify.
- ** deepCopy True if children of object are to also be copied into the undo stack.
- ** RESULT: OSErr Most likely error is memFulErr.
- **
- ** Saves a copy of the child in the undo hierarchy for undo/redo purposes. */
-
-
-
- OSErr SwapChildren(short editType, TreeObjHndl hndla, short cnuma,
- TreeObjHndl hndlb, short cnumb);
- /*
- ** ¶ Swaps the child handles.
- **
- ** INPUT: editType Type of edit for posting undo tasks. For no undo posting, then
- ** pass in NO_EDIT as a value.
- ** hndla Parent of one of the two children to swap.
- ** cnuma Child number of one of the two children to swap.
- ** hndlb Parent of other child to swap.
- ** cnumb Child number of other child to swap.
- ** RESULT: OSErr Most likely error is memFulErr.
- **
- ** Swaps the child handles. */
-
-
-
- OSErr SwapTreeObjData(TreeObjHndl hndla, TreeObjHndl hndlb);
- /*
- ** ¶ Swaps the child data without swapping the handles.
- **
- ** INPUT: editType Type of edit for posting undo tasks. For no undo posting, then
- ** pass in NO_EDIT as a value.
- ** hndla Parent of one of the two children whose data is to be swapped.
- ** cnuma Child number of one of the two children whose data is to swapped.
- ** hndlb Parent of other child involved in swap.
- ** cnumb Child number of other child involved in swap.
- ** RESULT: OSErr Most likely error is memFulErr.
- **
- ** Swaps the child data without swapping the handles. */
-
-
-
- void DisposeObjAndOffspring(TreeObjHndl objHndl);
- /*
- ** ¶ This disposes of the object and any offspring of that object.
- **
- ** INPUT: objHndl Object to dispose (and all of its children).
- **
- ** This disposes of the object and any offspring of that object. It does not remove
- ** the object from the parent's child handle table. The common usage is to remove a
- ** hierarchy starting from the root object. */
-
-
-
- OSErr CopyChildren(TreeObjHndl shndl, TreeObjHndl dhndl);
- /*
- ** ¶ Copy the children (and their children) of one object to another.
- **
- ** INPUT: shndl Source object (whose children are copied).
- ** dhndl Destination object (where copies will be placed as children).
- ** RESULT: OSErr Most likely error is memFullErr.
- **
- ** Copies the children (and children below that and so on) of one object to another object.
- ** This is used internally by CopyChild for deep copies. */
-
-
-
- OSErr InsertChildHndl(TreeObjHndl parentHndl, TreeObjHndl childHndl, short childNum);
- /*
- ** ¶ Adds an existing child to a parent's child handle table.
- **
- ** INPUT: parentHndl Parent whose child handle table will have an entry inserted.
- ** childHndl Child handle to insert into parent handle
- ** childNum Index into child handle table for insert.
- ** RESULT: OSErr memFullErr
- **
- ** Adds an existing child to a parent's child handle table. */
-
-
-
- void DeleteChildHndl(TreeObjHndl parentHndl, short childNum);
- /*
- ** ¶ Removes a child from the parent's child handle table.
- **
- ** INPUT: parentHndl
- ** childNum
- **
- ** Removes a child from the parent's child handle table. Note that it does not delete
- ** the child. (Possibly a better name would have been DetachChild.) */
-
-
-
- TreeObjHndl GetRootHndl(TreeObjHndl hndl);
- /*
- ** ¶ Given an object handle, return the root handle.
- **
- ** INPUT: hndl Any handle in the document hierarchy.
- ** RESULT TreeObjHndl The root object ofthe hierarchy.
- **
- ** Given an object handle, return the root handle. This function simply iterates through
- ** to the object's parent until the parent reference is nil. It returns that object. */
-
-
-
- TreeObjHndl GetChildHndl(TreeObjHndl parentHndl, short cnum);
- /*
- ** ¶ Given a parent handle and a child number, this returns the child handle.
- **
- ** INPUT: parentHndl Object whose child table is to indexed.
- ** cnum Index into the parent's child table.
- ** To get the first child, pass in 0.
- ** To get the last child, pass in -1, or any
- ** number >= to the number of children.
- ** The number of children is (*parentHndl)->numChildren
- ** RESULT: TreeObjHndl The child indexed out of the parent's child table.
- **
- ** Given a parent handle and a child number, this returns the child handle. */
-
-
-
- TreeObjHndl *GetChildHndlPtr(TreeObjHndl parentHndl, short *childNum, short endCase);
- /*
- ** ¶ Return a pointer into the child handle table.
- **
- ** INPUT: parentHndl Object whose child table is to indexed.
- ** *childNum Index into the parent's child table.
- ** endCase How to handle the index-beyond-end case.
- ** If 0, then pointing just after the child handle table
- ** is invalid, and the pointer will be snapped to point
- ** to the last entry in the table. The purpose for this
- ** case is to reference or replace an existing entry.
- ** If 1, then pointing just after the child handle table
- ** is valid. The purpose for this case is to get a pointer
- ** for an insertion operation.
- ** RESULT: TreeObjHndl The child indexed out of the parent's child table.
- **
- ** Return a pointer into the child handle table. This also validates (and corrects) cnum so
- ** that it is in range, if possible. Depending on the usage, pointing to just after the child
- ** handle table is either valid or invalid. If a handle is being added to the table, then
- ** pointing just after the table is valid. If a handle is being removed or referenced, then
- ** pointing just after the table is invalid. The parameter endCase determines which case we are
- ** dealing with. If endCase is 0, then pointing just after the child handle table is invalid,
- ** and if the cnum value passed in causes this, then nil is returned for the pointer. If
- ** endCase is 1, then pointing just after the child handle table is okay, and therefore nil will
- ** never be returned as the pointer. Any cnum value out of range will be corrected
- ** (if possible) to be within range. */
-
-
-
- short GetChildNum(TreeObjHndl hndl);
- /*
- ** ¶ Given a child handle, return posstion of it in the parent's child handle table.
- **
- ** INPUT: hndl Handle to get child number for.
- **
- ** Given a child handle, this returns the child number of that handle in the parent's child
- ** handle table. */
-
-
-
- OSErr AdjustDataSize(TreeObjHndl hndl, long delta);
- /*
- ** ¶ Adjust the data size, greater or smaller, depending on sign of 'delta'.
- **
- ** INPUT: hndl Target hierarchical document object.
- ** delta Amount to increase or decrease data area size of object.
- **
- ** Adjusts the data size, either greater or smaller, depending on the sign of 'delta'.
- ** Since this modifies the child, if you are posting undo information, you need to call
- ** ModifyChild with an editType other than NO_EDIT prior to calling this. ModifyChild
- ** will post the appropriate undo information prior to the modification of the child. */
-
-
-
- OSErr SetDataSize(TreeObjHndl hndl, long newSize);
- /*
- ** ¶ Sets the data size to newSize.
- **
- ** INPUT: hndl Handle to alter size of data area.
- ** newSize New size of data area. If shrunk, data will be lost.
- **
- ** Sets the data size to newSize. */
-
-
-
- OSErr SlideData(TreeObjHndl hndl, long offset, long delta);
- /*
- ** ¶ Slide some of the data in data area of object while resizing data area.
- **
- ** INPUT: hndl Handle of object whose data area is to changed.
- ** offset First byte in data to move. All bytes from this byte to the end
- ** will be moved.
- ** delta Amount to move data.
- ** If delta > 0 then the handle is grown, and then the data is moved.
- ** If delta < 0 then the data is moved, and then the handle is shrunk.
- ** RESULT: OSErr Move likely error is memFullErr.
- **
- ** Slides some of the data in the data portion of the object starting at 'offset' by a 'delta'
- ** amount, either forward or backward, depending on the sign of 'delta'. */
-
-
-
- void *GetDataPtr(TreeObjHndl hndl);
- /*
- ** ¶ Returns a pointer to the beginning of the object's data area.
- **
- ** INPUT: hndl Object to generate a pointer to data area for.
- ** RESULT: void * Pointer to data area. Cast it to whatever is appropriate.
- **
- ** Returns a pointer to the beginning of the object's data area. THIS DOES NOT LOCK THE HANDLE!
- ** The pointer may become invalid if memory moves. */
-
-
-
- OSErr ReadTree(TreeObjHndl hndl, short fileRefNum);
- /*
- ** ¶ Read the designated AppsToGo file into ram.
- **
- ** INPUT: hndl Handle which will serve as the root for the hierarchy that is to be
- ** read in. This doesn't have to be a true root. It can be an existing
- ** node in a hierarchy. A branch will be created in this case.
- ** fileRefNum The reference number for a previously opened file. The file position
- ** should be set to point to a previously-saved AppsToGo hierarchy.
- ** RESULT: OSErr
- **
- ** Given an open file that has been previously written via WriteTree, this function is called
- ** to read the file data into ram. The root object for the file is already created by
- ** InitDocument. The file must be open, and the file position must be set to the byte location
- ** where the root object of the file starts. Once this is so, just call this function with a
- ** reference to the root object and the open file refrence number. */
-
-
-
- OSErr ReadTreeObjData(TreeObjHndl hndl, short fileRefNum);
- /*
- ** ¶ Read in dataSize number of bytes into the object.
- **
- ** INPUT: hndl Object to read disk data into the data area for.
- ** fileRefNum File to read from.
- ** RESULT: OSErr
- **
- ** Read in dataSize number of bytes into the object. */
-
-
-
- OSErr WriteTree(TreeObjHndl hndl, short fileRefNum);
- /*
- ** ¶ Stream a hierarchy to disk.
- **
- ** INPUT: hndl Top node of the tree or branch to be written to disk.
- ** fileRefNum File to write to.
- ** RESULT: OSErr
- **
- ** Given an open file that is ready to be written to, this function is called to write the file
- ** tree to the designated file. */
-
-
-
- OSErr WriteTreeObjData(TreeObjHndl hndl, short fileRefNum);
- /*
- ** ¶ Write out dataSize (field in hndl) number of bytes from the object.
- **
- ** INPUT: hndl Object whose data is to be written to disk.
- ** fileRefNum File to write data to.
- **
- ** Write out dataSize number of bytes from the object. */
-
-
-
- void DoBTreeMethod(TreeObjHndl hndl, short message, long data);
- /*
- ** ¶ Call each object of the tree (or branch) in back-to-front order.
- **
- ** INPUT: hndl Start of tree or branch for tree-walk.
- ** message Message to send to object.
- ** data Application-defined data, i.e., refcon.
- **
- ** Call the object for each member of the tree (or branch) starting from the back of the
- ** tree working forward.
- **
- ** __________
- **
- ** Also see: DoErrBTreeMethod, DoFTreeMethod, DoErrFTreeMethod. */
-
-
-
- OSErr DoErrBTreeMethod(TreeObjHndl hndl, short message, long data);
- /*
- ** ¶ Call each object of the tree (or branch) in back-to-front order and abort on error.
- **
- ** INPUT: hndl Start of tree or branch for tree-walk.
- ** message Message to send to object.
- ** data Application-defined data, i.e., refcon.
- ** RESULT: OSErr Error, if any, that caused abort.
- **
- ** Call the object for each member of the tree (or branch) starting from the back of the
- ** tree working forward. If an object returns an error, abort the rest of the walk.
- **
- ** __________
- **
- ** Also see: DoBTreeMethod, DoFTreeMethod, DoErrFTreeMethod. */
-
-
-
- void DoFTreeMethod(TreeObjHndl hndl, short message, long data);
- /*
- ** ¶ Call each object of the tree (or branch) in front-to-back order.
- **
- ** INPUT: hndl Start of tree or branch for tree-walk.
- ** message Message to send to object.
- ** data Application-defined data, i.e., refcon.
- **
- ** Call the object for each member of the tree (or branch) starting from the front of the
- ** tree working backward.
- **
- ** __________
- **
- ** Also see: DoBTreeMethod, DoErrBTreeMethod, DoErrFTreeMethod. */
-
-
-
- OSErr DoErrFTreeMethod(TreeObjHndl hndl, short message, long data);
- /*
- ** ¶ Call each object of the tree (or branch) in front-to-back order and abort on error.
- **
- ** INPUT: hndl Start of tree or branch for tree-walk.
- ** message Message to send to object.
- ** data Application-defined data, i.e., refcon.
- ** RESULT: OSErr Error, if any, that caused abort.
- **
- ** Call the object for each member of the tree (or branch) starting from the front of the
- ** tree working backward. If an object returns an error, abort the rest of the walk.
- **
- ** __________
- **
- ** Also see: DoBTreeMethod, DoErrBTreeMethod, DoFTreeMethod. */
-
-
-
- long DoTreeObjMethod(TreeObjHndl hndl, short message, long data);
- /*
- ¶ If the object has a method procedure, call it. If no method procedure, do nothing.
-
- Below is the list of standard messages, followed by a description of each and its use:
-
- #define INITMESSAGE 0 Additional object initialization.
- #define CREATEINIT 0 Object being initially created.
- #define WINDOWINIT 1 Document/object being assigned to a window.
- #define NOWINDOWINIT 2 Document/object being freed from a window.
-
- #define FREEMESSAGE 1 Additional object disposal.
-
- #define COPYMESSAGE 2 Additional object cloning.
-
- #define UNDOMESSAGE 3 Additional object undo.
- #define UNDOFROMDOC 0 Object leaving document.
- #define UNDOTODOC 1 Object returning to document.
-
- #define CONVERTMESSAGE 4 Hndl2ID or ID2Hndl conversions.
- #define CONVERTTOID 0 Convert handle references to ID references.
- #define CONVERTTOHNDL 1 Convert ID references to handle references.
-
- #define FREADMESSAGE 5 Read object data from file.
- #define FWRITEMESSAGE 6 Write object data to file.
-
- #define HREADMESSAGE 7 Read object data from handle.
- #define HWRITEMESSAGE 8 Write object data to handle.
-
- #define HITTESTMESSAGE 9 Test if object was hit.
- #define HITTESTOBJ 0 Test body of object for hit.
- #define HITTESTGRABBER 1 Test sizing parts for hit.
- #define CANBETARGET 2 Return true if object can become target.
- #define CANTAKEKEYS 3 Return true if target can take keys.
-
- #define GETRGNMESSAGE 10 Return object bounding box.
- #define GETBBOXMESSAGE 11 Return object bounding box.
- #define SETBBOXMESSAGE 12 Set object bounding box.
- #define SECTBBOXMESSAGE 13 Check if rect intersects object bounding box.
-
- #define TARGETMESSAGE 14 Set target status for object.
- #define TARGETOFF 0 Make the object no longer the target.
- #define TARGETON 1 Make the object the target.
-
- #define DRAWMESSAGE 15 Draw some form of the object.
- #define DRAWOBJ 0 Draw the object.
- #define ERASEOBJ 1 Draw the object.
- #define DRAWSELECT 2 Draw the selection portion of the object.
- #define DRAWGHOST 3 Draw an xor-ghost (for dragging) of the image.
- #define DRAWMASK 4 Draw a mask of the image (for offscreen layer masking.)
-
- #define PRINTMESSAGE 16 Print the object.
-
- #define VHMESSAGE 17 Format View Hierarchy information for the object.
-
-
- INITMESSAGE: This is called with a sub-message of what kind of init it is. The CREATEINIT
- sub-message indicates that the object is initially being created. This sub-message is in
- case there is additional data initialization that must occur. Depending on the object, there
- may be handles that need to be created off the object itself. It may not be a simple linear
- block of data. In these cases, you want to do this additional initialization when the
- INITMESSAGE is received.
- The WINDOWINIT sub-message is in case certain objects have a different state when the document
- has a window than when it doesn't. For example: If there were a TextEdit object, then when
- the file is initially read in and the CREATEINIT sub-message is passed to the object, there is
- no window to pass to TENew to create a new TextEdit record. The data has to be read in as
- regular text that has no TERecord yet. Once the document is assigned a window, a TERecord can
- be created for the object and the text data can be moved into the TERecord. This additional
- WINDOWINIT sub-message is defined for just such objects that you may create. Note that
- nowhere in the application framework is there a call that passes a WINDOWINIT sub-message.
- This would be an application-specific function, and therefore this call would belong in the
- application. The most likely place for this would be in the InitContent function for the
- application. You would do something like the following:
- DoFTreeMethod(root, INITMESSAGE, WINDOWINIT);
- This would pass each object in the document an INITMESSAGE with a sub-message of WINDOWINIT.
- The final sub-message is NOWINDOWINIT. This message occurs when a document is being detached
- from a window. If an object has to change state to accomodate being related to a window, then
- it would need to change state back when disassociated with that window.
-
- FREEMESSAGE: This is called due to DisposeChild being called. DisposeChild will
- dispose of simple objects that don't have additional handles of data. Any handles that were
- created at INITMESSAGE time should be disposed of when the FREEMESSAGE is received.
-
- COPYMESSAGE: When CopyChild is called, a new child is created via calling NewChild.
- Normally when NewChild is called, the object is called with INITMESSAGE. However,
- when a child is being copied, the data area is copied into the copy child. This data
- copy would clobber any handle references the newly created copy would have, thus orphaning
- those handles. For this reason, no INITMESSAGE was passed to the object by NewChild.
- The data was copied into the copy however, so any handle references in the copy aren't unique
- references. The original child has the same references. This isn't a good situation.
- The first thing that the code for the COPYMESSAGE needs to do is to send itself an
- INITMESSAGE so that unique handles for the copy are created. Once this is done, then
- the code for COPYMESSAGE can actually copy the data in these handles. Once this final
- copying is done, we have a complete and separate copy of the original child.
-
- UNDOMESSAGE: When the user performs an undo or redo, involved objects get passed
- this message. When an undo/redo occurs objects are either moving into or out of the
- document. Objects move back and forth between the document and the undo hierarchy.
- The sub-messages UNDOFROMDOC and UNDOTODOC determine the direction. There may be various
- tasks that need to be performed to this object and other parts of the document when an
- undo/redo occurs. When an undo of a DELETE_EDIT is performed, it is typical to select
- the portion of the document undeleted. The root object may hold the selection information.
- If this is the case, the object should call GetRootHndl and then adjust the selection
- accordingly. Note that the root object may turn out to be the undo hierarchy root object.
- If the object has been moved out of the document and into the undo hierarchy, this will
- turn out to be the case. In this instance nothing would have to be done. At least one
- message will be sent to the object while it is still in the document. The sub-message
- will then state whether the document is about to leave or just was added to the document.
- Let's say that the root object contains a count of the number of selected items. In this
- case, if the item is selected, and it is about to leave the document, then the count of
- items selected will need to be decremented. If the item has just moved into the document,
- then the item needs to be set as selected, plus the number of selected items count needs
- to be increased by 1.
- An additional call is made prior to any objects being moved. This is to globally prepare
- the document for an undo/redo operation. Given that the items involved in the undo/redo
- should be selected, this suggests that other selected items should be deselected prior
- to the undo/redo. This global undo/redo setup call is the place to do things like this.
- Also, once the undo/redo operation is complete and all objects involved in the operation
- are moved and messaged, a final call is made to clean up any unfinished undo/redo business.
- To recap the undo/redo procedure:
- 1) A global get-ready-to-undo/redo call is made. This function is called UndoFixup.
- It is passed a reference to the document, plus a sub-message stating that it is
- called for pre-undo/redo tasks or post-undo/redo tasks (in this case pre-undo/redo).
- 2) Each object involved in the undo/redo task is called with appropriate messages
- stating whether it is leaving or entering the document. Appropriate document
- maintenance tasks should be performed based on these messages/sub-messages.
- 1) UndoFixup is called a final time. Once again, it is passed a reference to the document,
- plus a sub-message stating that it is called for post-undo/redo tasks.
-
- CONVERTMESSAGE: This is called to convert handle references within an object to treeID
- values and visa versa, depending on the sub-message.
- For the sub-message CONVERTTOID: Prior to the first object being written to disk, DoNumberTree
- is called to assign a unique treeID to each object in the document. For each handle reference
- in an object, call Hndl2ID to convert it to a treeID value. Once the object is written to
- disk, the object will be called again with the sub-message CONVERTTOHNDL. This indicates that
- the handle references that were converted to treeID values should be converted back. Call
- ID2Hndl to do the reverse conversion.
- For the sub-message CONVERTTOHNDL: The entire document is in memory prior to ever receiving this
- message. In the case of writing a document to disk, the document is already in memory. For
- the case where a document is being opened, the entire document is first read in, and then
- objects are passed this message as an opportunity to convert treeID values into handle references.
- In either case, DoNumberTree will have already been called, so it is okay to call ID2Hndl.
-
- FREADMESSAGE: This is called to read in the data portion of an object. The header
- information has already been read in. Since the header information doesn't vary according
- to the object type, it can be read in generically. Also, the header information states what
- type the object is, so until it the header is read in, the object type can't be determined.
- If the data doesn't have any additional handle references, just call the default function
- to read in the data. The default function is called ReadTreeObjData. It will read in
- the number of bytes designated by the dataSize in the header, which has already been read in.
- If there is additional data for the object to be kept in handles, or some such other unique
- situation, the code to do this goes here.
-
- FWRITEMESSAGE: This is called to write out the data portion of an object. The header
- information has already been written. Since the header information doesn't vary according
- to the object type, it can be written generically. If the data doesn't have any additional
- handle references, just call the default function to write out the data. The default
- function is called WriteTreeObjData. It will write out the number of bytes designated by
- the dataSize in the header. If there is additional data for the object kept in handles, or
- some such other unique situation, the code to write this additional data goes here.
-
- HREADMESSAGE: This message is similar to FREADMESSAGE, except that the data is read from
- a handle instead of from disk. The assumption is that the data is already in a handle.
- A handle containing the object's data is passed in. The handle is the same size as the dataSize
- field for the object. If the object's data is flat, then you can simply do the following:
- case HREADMESSAGE:
- return(HReadTreeObjData(hndl, (Handle)data));
- break;
- If the object's data isn't flat, then you will have to move the data from the handle into the
- object as is appropriate for this object. The ability to stream data not only to the file,
- but to a handle is really convenient. By calling the TreeObj.c function HWriteTree, you can
- stream any tree (or branch) into a handle. You can then save the handle as a resource, or you
- can send it to another application via AppleEvents. Once read, it can be unstreamed by
- calling HReadTree.
-
- HWRITEMESSAGE: This message is similar to FWRITEMESSAGE, except that it is used to write
- the data into a handle. See the HREADMESSAGE for more info.
-
- HITTESTMESSAGE: This message is used for hit-testing of an object, along with various
- targeting and keystroke information for the object. See the DTS.Draw example for
- implementation details.
-
- GETRGNMESSAGE: This message is requesting that the object return a region that describes
- its shape.
-
- GETBBOXMESSAGE: This message is requesting that the object return a rectangle that encloses
- all portions of the object.
-
- SETBBOXMESSAGE: This message is used to change the size of the bounding rectangle for
- an object.
-
- SECTBBOXMESSAGE: This message is used to determine if the object's bounding rectangle
- intersects the given rectangle.
-
- TARGETMESSAGE: This message is how an object is made the target or not the target of keystrokes.
-
- DRAWMESSAGE: This message and sub-message is to tell the object to draw itself, and in
- what form.
-
- PRINTMESSAGE: This message is to tell the object to print itself. Assumably the data
- field will vary, according to the object type. Objects often print themselves differently
- than they draw, so specific object information will have to be passed in for these cases.
-
- VHMESSAGE: This message allows the object to format the data information that is viewed
- when using the View Hierarchy object viewing feature.
-
-
- As is evident from the above descriptions, the behaviors for the different types of objects
- is completely dependent on what is done for the various messages. To define an object type,
- you need to make an entry into two tables. These tables are:
- 1) gTreeObjMethods
- 2) gMinTreeObjSize
- These tables are found in the application file File.c. As you add objects to your application,
- just make entries for these new objects into these tables.
- If you want the default behaviors for an object, then use nil for the method procedure. If
- the method procedure is nil, then the object is passed no messages, as it is assumed that it
- is simple and generic enough to be handled automatically. If you need to handle just one
- message specifically , you will then need to define a method procedure. With method procedures,
- it is an all-or-nothing situation. If you set the method procedure to non-nil for an object,
- then that object will receive all messages. For these instances you can just call the default
- code directly, such as ReadTreeObjData and WriteTreeObjData for handling file I/O for
- the object.
-
-
- Since the object is a handle of three components, referencing the object as if it is unique
- can be a bit of a pain. The unique portion of the object, the data portion, is actually in
- the middle of the object. To syntactically fix this problem, you will want to define some
- macros for dereferencing into an object with appropriate object-type typecasting. In
- FileFormat.h you will find some such dereferencing macros. They are in the form:
-
- #define mDerefRoot(hndl) ((RootObj*)((*hndl) + 1))
-
- This macro allows you to write code that looks like the following:
-
- numSelected = mDerefRoot(root)->numSelected;
-
- The only danger with this is that the handle that is dereferenced doesn't have to be of type
- RootObj. It can be of any type. This is convenient and not. It allows objects of different
- types to be treated similarly or differently, whichever the code demands.
-
-
- There are two defines in FileFormat.h that I should mention. These are:
- 1) MAXNUMUNDOS
- 2) NUMSAVEUNDOS
-
- These govern the depth of the undo mechanism.
-
- MAXNUMUNDOS is the maximum number of undos that will be recorded before the oldest are
- automatically purged. This can be set up to 65535, if you so wish, although that will
- cause a lot of undo hierarchy object to be kept around and is more than any human user
- can comprehend.
-
- NUMSAVEUNDOS is the maximum number of undos that are saved along with the document. If this
- number if non-zero, then when the document is opened, the user may already have some undos
- that can be performed from the last editing session. Setting this constant to zero makes
- the application save no undos along with the document.
-
-
- It is generally better if your object's data area is flat. This is good for a number of reasons:
-
- 1) It allows you to use the default streaming functions for FREADMESSAGE, FWRITEMESSAGE,
- HREADMESSAGE, HWRITEMESSAGE.
- 2) Your application uses fewer handles. The more handles, the slower the memory manager gets.
-
- Of course, for some object, being completely flat is unreasonable. The framework supports both flat
- and non-flat objects, so the choice is yours.
-
- */
-
-
-
- void DoNumberTree(TreeObjHndl hndl);
- /*
- ** ¶ Number each member in the tree with a unique treeID.
- **
- ** INPUT: hndl Any member of the hierarchy to be numbered.
- **
- ** Number each member in the tree with a unique treeID. The tree is numbered sequentially from
- ** front to back. The first treeID number is 1. 0 is reserved for Hndl2ID/ID2Hndl conversions
- ** where it is possible that the handle value is nil. The nil handle will convert to 0, and
- ** convert back to nil. */
-
-
-
- void Hndl2ID(TreeObjHndl *hndl);
- /*
- ** ¶ Convert a handle reference into a treeID reference.
- **
- ** IN/OUT: Pointer to handle to convert to an ID. The ID is returned where the handle was.
- **
- ** This function is used to convert a handle reference into a treeID reference. A pointer to
- ** the handle reference is passed in. Typical usage will be where a handle object has a
- ** reference to another handle object. Handle object references aren't meaningful when saved
- ** to disk, and therefore don't persist in their native form. These handle references need to
- ** be converted into a treeID reference so that they can be saved. The tree first needs to be
- ** numbered so that the treeID references are unique and meaningful. The tree is numbered by
- ** first calling DoNumberTree(). It numbers all the members of the tree hierarchy uniquely
- ** and sequentially. */
-
-
-
- void ID2Hndl(TreeObjHndl refHndl, TreeObjHndl *hndl);
- /*
- ** ¶ Return an object handle, given a tree object ID and reference object.
- **
- ** INPUT: refHndl
- ** IN/OUT: hndl Input, holds a tree object ID.
- ** Output, holds an object handle.
- ** Given a tree object ID and a reference object (any member of the tree), return the
- ** cooresponding object handle. DoNumberTree() must be called prior to using this function,
- ** and after the last change to the tree, as it generates the object treeID numbers for the
- ** entire tree. */
-
-
-
- TreeObjHndl GetUndoHndl(TreeObjHndl hndl);
- /*
- ** ¶ Given an object handle, return the undo handle.
- **
- ** INPUT: hndl Any handle in the hierarchy.
- ** RESULT: TreeObjHndl The root object for the undo hierarchy.
- **
- ** Given an object handle, return the undo handle. */
-
-
-
- void NewUndo(TreeObjHndl hndl);
- /*
- ** ¶ Close an old undo task, in preparation for a new one.
- **
- ** INPUT: hndl Any handle in the hierarchy (reference handle).
- **
- ** Used to close out an old undo task. Closing out the old task means that any editing to the
- ** document will be recorded into a new undo task. Use this to separate two edits of the same
- ** edit type that would otherwise get recorded into the same undo task. */
-
-
-
- void RevertEdit(TreeObjHndl hndl, Boolean fixup);
- /*
- ** ¶ If an edit fails, it can be backed out of by calling this.
- **
- ** INPUT: hndl Any handle in the hierarchy (reference handle).
- ** fixup If true, then the document's undoFixup procedure is called
- ** both before and after the undo/redo operation.
- **
- ** If an edit fails, it can be backed out of by calling this. All edits that were done will be
- ** undone, thus recovering the state of the document prior to the edit. */
-
-
-
- void DoUndoTask(TreeObjHndl hndl, Boolean redo, Boolean fixup);
- /*
- ** ¶ Performs an undo/redo process for a document.
- **
- ** INPUT: hndl Any object in the document hierarchy.
- ** redo True if this is a redo, as opposed to an undo operation.
- ** fixup If true, then the document's undoFixup procedure is called
- ** both before and after the undo/redo operation.
- **
- ** Call this to undo or redo editing to the document. If redo is false, then it is an undo
- ** task. If fixup is true, then the fixup application's undo fixup procedure is called before
- ** and after the undo operation. */
-
-
-
- void DisableUndo(TreeObjHndl hndl);
- /*
- ** ¶ Dispose of all undo information and prevent further undo collection.
- **
- ** INPUT: hndl Any object in the hierarchy.
- **
- ** Dispose of all undo information and prevent further undo collection. Calling NewUndo
- ** will re-enable undo collection. */
-
-
-
- void DisposeUndos(TreeObjHndl hndl);
- /*
- ** ¶ Dispose of all undo information.
- **
- ** INPUT: hndl Any object in the hierarchy.
- **
- ** Dispose of all undo information. */
-
-
-
- Boolean PurgeUndo(TreeObjHndl hndl);
- /*
- ** ¶ Dispose of all undo information except the current undo.
- **
- ** INPUT: hndl Any object in the hierarchy.
- ** RESULT: Boolean True if something was purged.
- **
- ** Dispose of all undo information except the current undo. The current undo may still be
- ** active, and it may be needed to back out of an edit operation. */
-
-
-
- void GetUndoInfo(FileRecHndl frHndl, short *undoDepth, short *numUndos);
- /*
- ** ¶ Return the depth of the undo state, along with the number of undos.
- **
- ** INPUT: frHndl File reference to get undo information for.
- ** undoDepth Current depth into undo stack.
- ** numUndos Depth of undo stack.
- **
- ** Return the depth of the undo state, along with the number of undos. This is useful to
- ** determine if undo and redo operations are possible. If undoDepth is non-zero, then undo
- ** is possible. If numUndos is greater than undoDepth, then redo is possible. */
-
-
-
- OSErr DefaultFreeDocument(FileRecHndl frHndl);
- /*
- ** ¶ Dispose of the standard document and undo information.
- **
- ** INPUT: frHndl File reference getting freed.
- ** RESULT: OSErr Any error means that freeing may not have succeeded.
- ** An error here is very unlikely, as most things that are
- ** freed are handles, and they are simply disposed of.
- **
- ** This is called when the standard behavior of disposing of the standard document and undo
- ** hierarchies are to be disposed of. Only call this if you have chosen to use the default
- ** document support of AppsToGo.
- **
- ** __________
- **
- ** Also see: DefaultInitDocument. */
-
-
-
- OSErr DefaultInitDocument(FileRecHndl frHndl, short version, short numUndos, short numSaveUndos);
- /*
- ** ¶ Create the standard document and undo objects.
- **
- ** INPUT: frHndl File reference getting freed.
- ** version Version information to save into document.
- ** numUndos Number of undo levels to support (more undos, more memory).
- ** numSaveUndos Number of undo levels to save with the document.
- ** RESULT: OSErr The most likely error is memFullErr.
- **
- ** This is called when the standard document behavior is what is desired. Note that
- ** committing to the default document architecture means that you can call the other
- ** default document functions such as DefaultReadDocument, DefaultWriteDocument,
- ** DefaultFreeDocument, etc. */
-
-
-
- OSErr DefaultReadDocument(FileRecHndl frHndl);
- /*
- ** ¶ Dispose of the standard document and undo information.
- **
- ** INPUT: frHndl File reference getting freed.
- ** RESULT: OSErr Any error means that freeing may not have succeeded.
- ** An error here is very unlikely, as most things that are
- ** freed are handles, and they are simply disposed of.
- **
- ** This is called when the standard behavior of disposing of the standard document and undo
- ** hierarchies are to be disposed of. Only call this if you have chosen to use the default
- ** document support of AppsToGo.
- **
- ** __________
- **
- ** Also see: DefaultInitDocument. */
-
-
-
- OSErr DefaultReadDocumentFixup(FileRecHndl frHndl);
- /*
- ** ¶ Move undo tasks saved with document out of document and into undo hierarchy.
- **
- ** INPUT: frHndl File reference to do fixup to.
- ** RESULT: OSErr Most likely is memFullErr.
- **
- ** Move any undo tasks that were saved with the document out of the document and into the
- ** undo hierarchy. They were moved into the document when the document was saved so that
- ** the undo information could be saved with the document. */
-
-
-
- OSErr DefaultWriteDocument(FileRecHndl frHndl);
- /*
- ** ¶ Write a standard hierarchical document to disk.
- **
- ** INPUT: frHndl File reference for document to save.
- ** RESULT: OSErr
- **
- ** Write a standard hierarchical document to disk. The number of undos to save (indicated by
- ** the numSaveUndos field in the undo root) are first moved to the end of the document. The
- ** document is then saved starting with the document root. */
-
-
-
- /* These functions are called when the standard behaviors are what is desired.
- **
- ** DefaultInitDocument:
- ** Create a root object and an undo root object. The undo root has the numUndos
- ** and numSaveUndos values placed in it.
- **
- ** DefaultFreeDocument:
- ** Dispose of the document and undo information. It assumes a normal hierarchical
- ** document architecture and undo root for the document.
- **
- ** DefaultReadDocument:
- ** Read a standard hierarchical document from a file. It assumes that the document
- ** was written with DefaultWriteDocument. There may be handle-to-id conversions
- ** still to do. The entire document must first be read in before this can occur.
- ** A separate pass through the doucment is made, giving each object a chance to
- ** convert id's back into handle references.
- **
- ** DefaultReadDocumentFixup:
- ** Fixup the document that was just read in. When a document is written out using
- ** DefaultWriteDocument, some number of undo tasks may have been moved onto the
- ** end of the document. This function moves the undo tasks out of the document
- ** and into the undo root.
- **
- ** DefaultWriteDocument:
- ** Write a standard hierarchical document to disk. The number of undos to save
- ** (indicated by the numSaveUndos field in the undo root) are first moved to the
- ** end of the document. The document is then saved starting with the document
- ** root.
- */
-
-
-
- OSErr HReadTree(TreeObjHndl hndl, Handle tree);
- /*
- ** ¶ Unflatten a hierarchy that is flattened in the handle "tree".
- **
- ** INPUT: hndl Handle which will serve as the root for the hierarchy when unflattened.
- ** This doesn't have to be a true root. It can be an existing node in a
- ** hierarchy. A branch will be created in this case.
- ** tree The handle containing the flattened hierarchy.
- ** RESULT: OSErr
- **
- ** HReadTree stands for Handle-based ReadTree.
- **
- ** Given a handle containing a flatten hierarchy created via WriteTree, this function is called
- ** to unflatten the data into a hierarchy. */
-
-
-
- OSErr HReadBranch(TreeObjHndl hndl, Handle tree);
- /*
- ** ¶ Recursively dissects the handle into separate tree objects.
- **
- ** INPUT: hndl Root object (root or branch) to unflatten data into.
- ** tree Handle holding a flattened hierarchy.
- ** RESULT: OSErr
- **
- * HReadTree calls this to get the real work done. HReadTree is a front-end to this function
- ** for applications.
- **
- ** This function recursively dissects the handle into separate tree objects. The handle has
- ** previously had tree objects streamed into it. The public format is as follows:
- ** 1) object header
- ** 2) data length (4 bytes)
- ** 3) data
- **
- ** After the object is created, the header is moved into it. Then the data length is fetched
- ** and a data handle is created to hold the data portion of the streamed data for this object.
- ** Once the data handle holds the object data, the tree handle has the information for this
- ** object removed from it.
- ** After this data separation, we call the object and pass it the data handle. The object is
- ** responsible for interpreting the handle and initializing the data portion of the object
- ** with it. */
-
-
-
- OSErr HReadTreeObjData(TreeObjHndl hndl, Handle treeObjData);
- /*
- ** ¶ Get the object data from the stream.
- **
- ** INPUT: hndl Handle to receive object data.
- ** treeObjData Remains of flattened hierarchy.
- ** RESULT: OSErr
- **
- ** The simple handle read can assume that there will be no expansion or interpretation of the
- ** data. This means that the dataSize field represents the correct data size. */
-
-
-
- OSErr HWriteTree(TreeObjHndl hndl, Handle tree);
- /*
- ** ¶ Stream the hierarchy onto the end of the handle.
- **
- ** INPUT: hndl Root object of document or branch to stream into handle.
- ** tree Handle receive flattened data. Data is appended to end of handle.
- **
- ** Given a handle, this function is called to stream the hierarchy onto the end
- ** of the handle. */
-
-
-
- OSErr HWriteTreeObjData(TreeObjHndl hndl, Handle data);
- /*
- ** ¶ Append data in object onto end of handle receiving streamed hierarchy.
- **
- ** INPUT: hndl Object whose data is to be appended to the receiving handle.
- ** data Handle receiving flattened hierarchy, and in this case the data
- ** data portion of a single object. The object data is appended to
- ** the end of the handle.
- ** RESULT: OSErr
- **
- ** Given an object, append its data onto the end of a handle which is receiving a flattened
- ** hierarchy. Each object is streamed into the flattened hierarchy handle in two steps:
- ** 1) The header of the object.
- ** 2) The data area of the object.
- **
- ** HWriteTreeObjData is the default action for step 2. */
-
-
-
- long GetCData(TreeObjHndl hndl, long offset, char *data);
- /*
- ** ¶ Given an offset in the object's data, get the 0-terminated data.
- **
- ** INPUT: hndl Object to get data from.
- ** offset Offset into the data area of the object.
- ** data Pointer to where to place the received data.
- ** (If nil, no data transfer occurs, but the length is still returned.)
- ** RESULT: long Length of data gotten (or measured).
- **
- ** This is used to copy 0-terminated data out of an object, given the offset of the data.
- ** The offset is generally gotten by calling GetDataOffset for complex data types. If the
- ** data for the object is a single c-string (or a c-string at the end of a fixed block), then
- ** you can simply use the macro “offsetof” to get the offset to the c-string. If you have
- ** multiple packed c-strings, then you need to use GetDataOffset to determine the offset for
- ** c-strings after the first. (The first starts at a fixed location, so therefore it has
- ** a constant offset.)
- **
- ** __________
- **
- ** Also see: PutCData, GetDataOffset. */
-
-
-
- OSErr PutCData(TreeObjHndl hndl, long offset, char *data);
- /*
- ** ¶ Given an offset in the object's data, replace the old 0-terminated data.
- **
- ** INPUT: hndl Object to store data.
- ** offset Offset into the data area of the object.
- ** data Pointer to the data to save.
- ** RESULT: OSErr Most likely error is memFullErr.
- **
- ** This is used to save 0-terminated data into an object, given the offset of the data.
- ** The offset must reference a 0-terminated data location, since this operation will
- ** replace the previous 0-terminated data element.
- **
- ** The offset is generally gotten by calling GetDataOffset for complex data types. If the
- ** data for the object is a single c-string (or a c-string at the end of a fixed block), then
- ** you can simply use the macro “offsetof” to get the offset to the c-string. If you have
- ** multiple packed c-strings, then you need to use GetDataOffset to determine the offset for
- ** c-strings after the first. (The first starts at a fixed location, so therefore it has
- ** a constant offset.)
- **
- ** __________
- **
- ** Also see: GetCData, GetDataOffset. */
-
-
-
- void GetPData(TreeObjHndl hndl, long offset, StringPtr data);
- /*
- ** ¶ Given an offset in the object's data, get the pascal string data.
- **
- ** INPUT: hndl Object to get data from.
- ** offset Offset into the data area of the object.
- ** data Pointer to where to place the received data.
- ** (If nil, no data transfer occurs, but the length is still returned.)
- ** RESULT: long Length of data gotten (or measured).
- **
- ** This is used to copy pascal string data out of an object, given the offset of the data.
- ** The offset is generally gotten by calling GetDataOffset for complex data types. If the
- ** data for the object is a single pascal-string (or a pascal-string at the end of a fixed
- ** block), then you can simply use the macro “offsetof” to get the offset to the pascal-string.
- ** If you have multiple packed pascal-strings, then you need to use GetDataOffset to determine
- ** the offset for pascal-strings after the first. (The first starts at a fixed location, so
- ** therefore it has a constant offset.)
- **
- ** __________
- **
- ** Also see: PutPData, GetDataOffset. */
-
-
-
- OSErr PutPData(TreeObjHndl hndl, long offset, StringPtr data);
- /*
- ** ¶ Given an offset in the object's data, replace the old pascal data.
- **
- ** INPUT: hndl Object to store data.
- ** offset Offset into the data area of the object.
- ** data Pointer to the data to save.
- ** RESULT: OSErr Most likely error is memFullErr.
- **
- ** This is used to save a pascal string into an object, given the offset of the data.
- ** The offset must reference a pascal string location, since this operation will
- ** replace the previous pascal string data element.
- **
- ** The offset is generally gotten by calling GetDataOffset for complex data types. If the data
- ** for the object is a single pascal-string (or a pascal-string at the end of a fixed block),
- ** then you can simply use the macro “offsetof” to get the offset to the pascal-string. If you
- ** have multiple packed pascal-strings, then you need to use GetDataOffset to determine the
- ** offset for pascal-strings after the first. (The first starts at a fixed location, so
- ** therefore it has a constant offset.)
- **
- ** __________
- **
- ** Also see: GetPData, GetDataOffset. */
-
-
-
- OSErr PutShortData(TreeObjHndl hndl, long offset, void *data, unsigned short size);
- /*
- ** ¶ Store block of short data (data length < 64k) into object, replacing old block.
- **
- ** INPUT: hndl Object to store data into.
- ** offset Offset (from beginning of data area) of where to store data.
- ** Note that this is a replace action, so there needs to be a
- ** short data element already at offset.
- ** data Pointer to short data.
- ** size Size of data.
- ** RESULT: OSErr
- **
- ** This is used to store blocks of data of max size < 64k into the data area of the object.
- ** Note that this operation replaces the previous short data block, so therefore the offset
- ** must be validly referencing a short data element in the object.
- **
- ** Below is some sample code which demonstrates saving a TextEdit text data block and
- ** style block into an AppsToGo CtlObj object:
- **
- ** hh = (*te)->hText;
- ** nn = (*te)->teLength;
- ** oo = GetDataOffset(cobj, offsetof(CtlObj,title), kPStr, 4);
- ** HLock(hh);
- ** PutShortData(cobj, oo, *hh, nn);
- ** HUnlock(hh);
- **
- ** oo = GetDataOffset(cobj, oo, kSDataBlock, 1);
- ** if (styl = CTEGetFullStylScrap(te)) {
- ** HLock((Handle)styl);
- ** PutShortData(cobj, oo, (Ptr)*styl, GetHandleSize((Handle)styl));
- ** HUnlock((Handle)styl);
- ** }
- ** else
- ** PutShortData(cobj, oo, nil, 0);
- **
- ** The first GetDataOffset starts at the fixed offset where the pascal string data starts.
- ** It skips over the 4 pascal strings to return the offset to the first short data block,
- ** which is the text of the TextEdit record. Once the offset is obtained, the text handle
- ** is locked, and then PutShortData is called to replace the old text block in the object.
- **
- ** Once the text block is replaced, GetDataOffset is used to get the offset of the next
- ** short block of data, which is stored immediately after the text block. The data is then
- ** saved via a second call to PutShortData.
- **
- ** Note that when writing the style block, we don't even necessarily have a style block.
- ** Ths styl handle may be returned as nil. In this case, we write out 0 bytes, thus replacing
- ** the old data block with an empty data block. */
-
-
-
- OSErr PutLongData(TreeObjHndl hndl, long offset, void *data, long size);
- /*
- ** ¶ Store block of long data (length which may be > 64k) into object, replacing old block.
- **
- ** INPUT: hndl Object to store data into.
- ** offset Offset (from beginning of data area) of where to store data.
- ** Note that this is a replace action, so there needs to be a
- ** long data element already at offset.
- ** data Pointer to long data.
- ** size Size of data.
- ** RESULT: OSErr
- **
- ** This is used to store blocks of data into the data area of the object. Note that this
- ** operation replaces the previous short data block, so therefore the offset must be validly
- ** referencing a short data element in the object.
- **
- ** Below is some sample code which demonstrates writing a handle of data "hh" into the
- ** object at offset "oo":
- **
- ** HLock(hh);
- ** PutLongData(cobj, oo, *hh, GetHandleSize(hh));
- ** HUnlock(hh);
- **
- ** For an example of determining the offset to place the data, see PutShortData. The only
- ** difference between the two calls is the size of the data element. How you use the calls
- ** is the same. */
-
-
-
- unsigned long GetDataOffset(TreeObjHndl hndl, unsigned long offset, short dtype, short dnum);
- /*
- ** ¶ Get pointer into data area of object for complex data area definitions.
- **
- ** INPUT: hndl Handle to reference into to generate offset.
- ** offset Starting offset to advance from.
- ** dtype Type of data to traverse.
- ** dnum Number of data elements to traverse.
- ** RESULT: long Advanced offset value after traversing data elements.
- **
- ** GetDataOffset is the key call. It allows you to calculate an offset into the objects data,
- ** even if the data in front of it is of variable size. Let's takle a look at an object that is
- ** quite variable. You will find the following typedef in the file DTS.Lib.h:
- **
- ** typedef struct {
- ** short numRows;
- ** short numCols;
- ** short cellHeight;
- ** short cellWidth;
- ** short mode;
- ** } CLNewInfo;
- ** typedef struct {
- ** Rect destRct;
- ** Rect viewRct;
- ** Rect brdrRct;
- ** short maxTextLen;
- ** short mode;
- ** } CTENewInfo;
- ** typedef struct {
- ** short selected;
- ** Rect rect;
- ** char visible;
- ** char hilite;
- ** short value, min, max;
- ** short procID;
- ** long refCon;
- ** short ctlID;
- ** short cctbID;
- ** short fontSize;
- ** Style fontStyle;
- ** union {
- ** CLNewInfo clnew;
- ** CTENewInfo ctenew;
- ** } extCtl;
- ** unsigned char title[4]; 4 pascal strings are stored back-to-back starting here.
- ** title[0] = control title
- ** title[1] = key equivs
- ** title[2] = control font
- ** title[3] = balloon help info
- ** short textLen[2]; 2 short-prefixed data blocks stored starting here.
- ** textLen[0] = textEdit control text block
- ** textLen[1] = textEdit control style block
- ** } CtlObj;
- ** #define mDerefCtl(hndl) ((CtlObj*)((*hndl) + 1))
- **
- ** Everything is reasonable until we get to the textLen field. If we were to get the offset
- ** of this field using the offsetof macro (found in Utilities.h), we would get a value that is
- ** 4 bigger than the offset for the title field. This is initially true if the struct is filled
- ** with zeros. (We would then have 4 zero-length pascal strings in front on textLen). Once we
- ** modify one of these title strings, then the textLen data would slide down.
- **
- ** There are 4 data types that GetDataOffset can traverse. They are:
- ** #define kCStr 0 (See GetCData and PutCData)
- ** #define kPStr 1 (See GetPData and PutPData)
- ** #define kSDataBlock 2 (See PutShortData)
- ** #define kLDataBlock 3 (See PutLongData)
- **
- ** To get the correct offset for textLen[1], we would do the following:
- **
- ** ofst = GetDataOffset(hndl, offsetof(CtlObj,title), kPStr, 4);
- ** This gets us past the 4 pascal strings.
- **
- ** ofst = GetDataOffset(hndl, ofst, kSDataBlock, 1);
- ** This gets us past the first short block of data. A short block of data is a 2-byte
- ** data length, followed by the data. Note that even though textLen is a signed short,
- ** GetDataOffset treats it as unsigned. This allows us to be a bit more descriptive
- ** in our typedef. By stating that it is a short, we are indicating that we don't
- ** expect the data to get bigger than 32767.
- **
- ** Now that we have this offset, we can use the PutShortData() call to replace this data.
- ** Let's assume that we have a handle of text called txtHndl, and the length is txtLen. To
- ** replace the old block of data with this text, we would make the following call:
- **
- ** err = PutShortData(hndl, ofst, txtHndl, txtLen);
- **
- ** Any data fields that are after this field are moved to adjust for the size differences
- ** between the data being replaced and the new data.
- **
- ** Long data blocks are also supported, as well as C and pascal string data types.
- ** There are also Get functions for the string types, but there aren't for the block types.
- ** The assumption is that you will need to create a handle to copy the data into. To get a
- ** data block, first generate the offset, then get the short or long for the data size. Create
- ** a handle of this size, and then BlockMove the data.
- **
- ** To get the data for this short block, the code would look like this:
- **
- ** short ofst;
- ** Ptr dptr;
- **
- ** ofst = GetDataOffset(hndl, offsetof(CtlObj,title), kPStr, 4);
- ** ofst = GetDataOffset(hndl, ofst, kSDataBlock, 1);
- ** dptr = GetDataPtr(hndl);
- ** BlockMove(dptr + ofst, &dsiz, sizeof(short));
- ** dhndl = NewHandle(dsiz);
- ** if (dhndl) {
- ** dptr = GetDataPtr(hndl);
- ** BlockMove(dptr + ofst, *dhndl, dsiz);
- ** }
- **
- ** Not too bad for fetching a variable-length field from a variable location.
- **
- ** Of course, for strings, it's a snap. Here's the code to get title[2]:
- **
- ** short ofst;
- ** Str255 pstr;
- **
- ** ofst = GetDataOffset(hndl, offsetof(CtlObj,title), kPStr, 2);
- ** GetPData(hndl, ofst, pstr);
- */
-
-
- Boolean EqualTreeObjData(TreeObjHndl h1, TreeObjHndl h2);
- /*
- ** ¶ Compare the data area of two TreeObj objects.
- **
- ** INPUT: h1 One of two handles for compare.
- ** h2 Other handle for compare.
- ** RESULT: Boolean True if data areas are the same.
- **
- ** Call this function to compare two TreeObj objects. If there is no procPtr defined for the
- ** object, then this function calls DefaultEqualTreeObjData to do the comparison. If you have
- ** a procPtr defined for the function, then you will probably want to call
- ** DefaultEqualTreeObjData from within your object when you get a COMPAREMESSAGE.
- ** DefaultEqualTreeObjData simply does a byte-per-byte comparison, and if any difference is
- ** found, it returns false. If all of the bytes are the same, then it returns true. For deep
- ** objects, you will have to write your own comparison. If you have a handle stored in the
- ** object, then you will need to compare the contents of the handle, instead of the handle
- ** itself. DefaultEqualTreeObjData doesn't know that the data is actually a handle.
- ** DefaultEqualTreeObjData does a flat compare. */
-
- Boolean DefaultEqualTreeObjData(TreeObjHndl h1, TreeObjHndl h2);
- /*
- ** ¶ The default object comparison function.
- **
- ** INPUT: h1 One of two handles for compare.
- ** h2 Other handle for compare.
- ** RESULT: Boolean True if data areas are the same.
- **
- ** The default object comparison function. This simply does a flat-compare of the
- ** two objects.
- **
- ** __________
- **
- ** Also see: EqualTreeObjData. */
-
-
- #endif
-